```python
import json
from typing import Any, Optional

from pydantic import Field

from app.agent.toolcall import ToolCallAgent
from app.logger import logger
from app.prompt.browser import NEXT_STEP_PROMPT, SYSTEM_PROMPT
from app.schema import Message, ToolChoice
from app.tool import BrowserUseTool, Terminate, ToolCollection


class BrowserAgent(ToolCallAgent):
    """
    A browser agent that uses the browser_use library to control a browser.

    该代理可以通过浏览器控制库来控制浏览器，执行诸如导航网页、与元素交互、填写表单、
    提取内容以及其他基于浏览器的行为，以完成任务。
    """

    name: str = "browser"
    description: str = "A browser agent that can control a browser to accomplish tasks"

    system_prompt: str = SYSTEM_PROMPT
    next_step_prompt: str = NEXT_STEP_PROMPT

    max_observe: int = 10000
    max_steps: int = 20

    # 配置可用的工具
    available_tools: ToolCollection = Field(
        default_factory=lambda: ToolCollection(BrowserUseTool(), Terminate())
    )

    # 使用 Auto 作为工具选择，以允许工具使用和自由形式的响应
    tool_choices: ToolChoice = ToolChoice.AUTO
    special_tool_names: list[str] = Field(default_factory=lambda: [Terminate().name])

    _current_base64_image: Optional[str] = None

    async def _handle_special_tool(self, name: str, result: Any, **kwargs):
        """
        处理特殊工具的调用结果。

        参数:
            name (str): 工具名称
            result (Any): 工具调用结果
            **kwargs: 其他关键字参数

        如果工具不是特殊工具，则直接返回。否则，清理浏览器工具并调用父类的处理方法。
        """
        if not self._is_special_tool(name):
            return
        else:
            await self.available_tools.get_tool(BrowserUseTool().name).cleanup()
            await super()._handle_special_tool(name, result, **kwargs)

    async def get_browser_state(self) -> Optional[dict]:
        """
        获取当前浏览器的上下文状态，以便在下一步中使用。

        返回:
            Optional[dict]: 包含浏览器状态的字典，如果获取失败则返回 None
        """
        browser_tool = self.available_tools.get_tool(BrowserUseTool().name)
        if not browser_tool:
            return None

        try:
            # 直接从工具中获取浏览器状态
            result = await browser_tool.get_current_state()

            if result.error:
                logger.debug(f"浏览器状态错误: {result.error}")
                return None

            # 如果有截图则存储
            if hasattr(result, "base64_image") and result.base64_image:
                self._current_base64_image = result.base64_image

            # 解析状态信息
            return json.loads(result.output)

        except Exception as e:
            logger.debug(f"获取浏览器状态失败: {str(e)}")
            return None

    async def think(self) -> bool:
        """
        处理当前状态并决定下一步操作，使用工具并添加浏览器状态信息。

        返回:
            bool: 处理结果
        """
        # 将浏览器状态添加到上下文中
        browser_state = await self.get_browser_state()

        # 初始化占位符值
        url_info = ""
        tabs_info = ""
        content_above_info = ""
        content_below_info = ""
        results_info = ""

        if browser_state and not browser_state.get("error"):
            # URL 和标题信息
            url_info = f"\n   URL: {browser_state.get('url', 'N/A')}\n   Title: {browser_state.get('title', 'N/A')}"

            # 标签页信息
            if "tabs" in browser_state:
                tabs = browser_state.get("tabs", [])
                if tabs:
                    tabs_info = f"\n   {len(tabs)} tab(s) available"

            # 视口上方/下方的内容
            pixels_above = browser_state.get("pixels_above", 0)
            pixels_below = browser_state.get("pixels_below", 0)

            if pixels_above > 0:
                content_above_info = f" ({pixels_above} pixels)"

            if pixels_below > 0:
                content_below_info = f" ({pixels_below} pixels)"

            # 如果有截图则添加为 base64
            if self._current_base64_image:
                # 创建包含图片附件的消息
                image_message = Message.user_message(
                    content="Current browser screenshot:",
                    base64_image=self._current_base64_image,
                )
                self.memory.add_message(image_message)

        # 用实际的浏览器状态信息替换占位符
        self.next_step_prompt = NEXT_STEP_PROMPT.format(
            url_placeholder=url_info,
            tabs_placeholder=tabs_info,
            content_above_placeholder=content_above_info,
            content_below_placeholder=content_below_info,
            results_placeholder=results_info,
        )

        # 调用父类实现
        result = await super().think()

        # 将 next_step_prompt 重置为其原始状态
        self.next_step_prompt = NEXT_STEP_PROMPT

        return result
```